Skip to content

[scautoloc] Add location-dependent depth lookup (Slab2 backend)#126

Open
comoglu wants to merge 12 commits into
SeisComP:mainfrom
comoglu:feature/depthlookup-v2
Open

[scautoloc] Add location-dependent depth lookup (Slab2 backend)#126
comoglu wants to merge 12 commits into
SeisComP:mainfrom
comoglu:feature/depthlookup-v2

Conversation

@comoglu

@comoglu comoglu commented Jul 9, 2026

Copy link
Copy Markdown
Contributor

Summary

Adds location-dependent defaultDepth and maxDepth to scautoloc via a
small abstract DepthLookup interface compiled directly into the binary.

Two backends ship:

  • Constant — returns fixed values from autoloc.defaultDepth /
    autoloc.maxDepth. This is the default; existing behaviour is unchanged.
  • Slab2 — looks up depth from USGS Slab2.0 depth-footprint contour files
    (BNA, 27 slab zones, 35 depth levels at 20 km intervals, 000–680 km).

The implementation is intentionally self-contained: no plugin loader, no
Client::Application dependency. Safe for standalone use and Python scripts.

New config keys

autoloc.depthLookup = Constant          # default — existing behaviour
autoloc.depthLookup = Slab2             # geographic lookup
# autoloc.slab2.directory auto-resolves to share/scautoloc/slabs/

New files

Path Description
apps/processing/scautoloc/depthlookup.h Abstract interface + backend declarations
apps/processing/scautoloc/depthlookup.cpp Constant and Slab2 implementations
apps/processing/scautoloc/share/slabs/ 531 USGS Slab2.0 BNA files

Integration points in autoloc.cpp

All _config.defaultDepth call sites replaced by _depthLookup->fetch(lat, lon);
all _config.maxDepth checks replaced by _depthLookup->fetchMaxDepth(lat, lon).

Test results (4 pick files, 2026-06-05)

With Slab2 vs Constant:

Location Constant Slab2
Tonga (−22.3°S, −176.9°W) 10 km 140 km
New Zealand (−41.6°S, 173.2°E) 10 km 325 km
Central America (13.4°N, −87.5°W) 10 km 82 km
Honduras deep zone no solution 504–544 km solutions found

Relationship to seiscomp/common PR #199

SeisComP/common#199 (Seiscomp::Seismology::DepthLookup) provides an
abstract factory interface for other SC modules. This PR is independent —
scautoloc's interface lives in Seiscomp::Processing and has no dependency
on the common factory system. The two can coexist; a Slab2 plugin for the
common interface can be added separately if desired.

comoglu added 10 commits June 4, 2026 21:43
Replace fixed locator.defaultDepth and autoloc.maxDepth with a
geographic DepthLookup system compiled directly into scautoloc.

No plugin loader, no Client::Application dependency — safe to use
from standalone code and Python scripts.

Backends (selected via autoloc.depthLookup):
  Constant (default) — uses existing defaultDepth/maxDepth config
                       values unchanged; zero behaviour change for
                       existing deployments
  Slab2              — USGS Slab2.0 depth-footprint contours; depth
                       and maxDepth vary by geographic location

Config:
  autoloc.depthLookup        = Constant | Slab2
  autoloc.slab2.directory    = path to BNA contour files
- Add 531 USGS Slab2.0 depth-contour BNA files (35 depth levels,
  27 slab zones) installed to share/scautoloc/slabs/
- Update config.cpp dump() to show depthLookup type and slabDir
- Update scautoloc.xml with depthLookup and slab2.directory params
- Fix feature name to match BNA header format: 'zone depth km'
- Initialize _depthLookup in constructor to prevent null dereference
  if init() is bypassed or fails early
- Use Environment::absolutePath(configGetString()) for slabDir,
  consistent with gridConfigFile/staConfFile pattern
Use Environment::shareDir() in catch block so the default
slabs path is correctly resolved even when autoloc.slab2.directory
is not explicitly configured.
Two bugs fixed:
- BNA files had negative vertex counts (-N) which SC's GeoFeature
  treats as open polygons (closedPolygon=false), making contains()
  always return false. Changed to positive counts so polygons are
  loaded as closed and contains() works correctly.
- _lookupDepth/_fetchMaxDepth: check all sub-polygons per zone level
  (some zones have multiple sub-polygons with the same name).
- Rename _dd → dd and _maxDep → maxDep (leading underscore is for
  class members only, not local variables)
- Fix typo: "objects(s)" → "object(s)"
@cla-bot cla-bot Bot added the cla-signed The CLA has been signed by all contributors label Jul 9, 2026
Adds fetchCandidateDepths() to the DepthLookup interface (default wraps
fetch(), returns single depth — existing behaviour unchanged).

Slab2 backend overrides it: inside a slab zone returns {slabDepth,
fallbackDepth} so both the deep slab seed and the shallow crustal seed
are evaluated. Outside all zones returns {fallbackDepth} as before.

_setDefaultDepth() now iterates all candidates and keeps the
best-scoring relocation, enabling correct depth assignment in regions
with dual seismicity (e.g. Tonga: 140 km slab vs 10 km crustal).
AutolocInternal::OriginVector _origins;
AutolocConfig _config;
AutolocInternal::StationConfig _stationConfig;
DepthLookupPtr _depthLookup;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is one DepthLookup. That would mean that scautoloc can use either DepthLookupPolygon or Slab2DepthLookup, right? But what if it needs to use both? The common use case is: Slabs in subduction zones but also regions which only have induced seismicity where I need to fix the depth to a regional default no matter what. Or think of ocean ridges and transform faults, where the value DepthLookupPolygon would be that I can specify explicitly "for this region fix the depth and don't try different depths". Currently there is a default depth but scautoloc always performs some tests to see if an event could be deeper. And occasionally the result is wrong, e.g. if an event at a mid-ocean ridge is located at 120 km depth. DepthLookupPolygon can prevent that very effectively. But ideally not at the expense of Slab2DepthLookup.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The idea of the DepthLookup is to outsource that knowledge. If you need a version of DepthLookup with all your special code paths then implement an DepthLookupAutoloc which internally instantiates both classes and does all the processing. scautoloc should just query one interface regardless of the implementation. Think of it as a RecordStream.

@comoglu comoglu Jul 15, 2026

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @gempa-jabe
This makes perfect sense, so a DepthLookupComposite (or whatever we call it) in seiscomp/common internally combines Polygon + Slab2 + Constant with priority ordering. scautoloc just queries one interface and doesn't care what's underneath.

That also means Slab2 should move to common, which is what @jsaul was asking for.

One thing I want to flag @jsaul before I start working on it, the original reason I kept it self-contained in scautoloc was @jsaul 's goal of calling autoloc from Python/ObsPy without the full SC environment. Moving to the factory + init(Config::Config&) pattern brings that dependency back in. Is that still a concern, or has that goal changed?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't get on it too fast. I am not saying that we need to implement everything in common. I am saying that the strength of the DepthLookup interface is that we are able to remove the complexity of that operation from the client. Having that said, stick to the current implementation in common and add everything needed here to get a proof of concept. I know that an implementation change is just one Claude prompt away but doing that in common is wrong at this stage. The interface is there, two simple example implementations are there and more complex stuff can be added later once proven its usefulness. Please learn your lessons with scautoloc first.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Noted, will hold off and will work on proving the concept in scautoloc first. Thanks, @gempa-jabe .

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There are several misunderstandings involved and I think we should not discuss everything here on Github (i.e. in public).

Anyway, the Slab2DepthLookup should not be provided through scautoloc. Doesn't have to be in common either, could also be under https://github.com/comoglu - as long as it remains installable. That's the advantage of making it a plugin and not a library function.

@comoglu comoglu Jul 16, 2026

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Polygon backend queries named GeoFeature regions from the global
GeoFeatureSet. Each region carries a defaultDepth attribute (required)
and optionally maxDepth. covers() returns true only when the epicenter
is inside a named polygon, so it acts as an explicit override layer.

Composite backend chains backends in priority order — Polygon first,
then Slab2, then Constant — delegating all three methods (fetch,
fetchMaxDepth, fetchCandidateDepths) to the first backend where
covers() returns true.

covers() added to DepthLookup base (default true); Polygon and Slab2
override it to signal positive identification vs fallback.

Config:
  autoloc.depthLookup = Composite
  autoloc.polygon.regions = induced_seismicity_zone, mid_ocean_ridges
  autoloc.slab2.directory = @datadir@/scautoloc/slabs
@comoglu

comoglu commented Jul 16, 2026

Copy link
Copy Markdown
Contributor Author

@jsaul @gempa-jabe

Just to clarify what those two repos are:

The plugin repo (seiscomp-slab2-plugin) is a standalone SeisComP plugin that implements the DepthLookup interface from common PR #199. It registers a "Slab2" backend that reads USGS Slab2.0 BNA files from share/spatial/vector/slab2 (the same path scolv uses for display, so no duplicate data). I've tested it with live global traffic and depth lookups are firing correctly, e.g Philippines 80 km, Kuril 40 km etc.

The feature/depthlookup-factory branch (Draft PR #127) is the scautoloc side : it replaces the compiled-in depth logic with DepthLookupFactory::Create() so any registered plugin can be loaded at runtime. There's one new config key autoloc.depthLookup which defaults to "Constant", meaning zero behaviour change if the plugin isn't loaded.

The two are independent. The plugin can work with any module that supports the DepthLookup interface. The scautoloc PR only becomes relevant once you guys are happy with the interface design.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

cla-signed The CLA has been signed by all contributors

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants